package jdos.cpu;

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Vector;

import jdos.cpu.core_normal.Code;
import jdos.cpu.core_normal.CodeExt;
import jdos.cpu.core_normal.Prefix_helpers;
import jdos.cpu.core_normal.Prefix_helpers.OP;
import jdos.cpu.core_normal.Prefix_helpers.PREFIX;
import jdos.hardware.Memory;
import jdos.misc.Log;
import jdos.misc.setup.Config;
import jdos.types.LogSeverities;
import jdos.types.LogTypes;

public class Core_full {

	static OutputStreamWriter osw;

	static void logWrite(String s) {
		if (Log.level<=LogSeverities.LOG_NORMAL) {
			try {
				osw.write(s);
				osw.write(' ');
				osw.flush();
			} catch (Throwable t) {

			}
		}
	}

	static void logIns(int c) {
		if (Log.level<=LogSeverities.LOG_NORMAL) {
			try {
				osw.write(Integer.toString(c, 16));
				osw.write(' ');
				osw.flush();
			} catch (Throwable t) {

			}
		}
	}

	static void logInsNewLine() {
		if (Log.level<=LogSeverities.LOG_NORMAL) {
			try {
				osw.write("\r\n");
				osw.flush();
			} catch (Throwable t) {

			}
		}
	}


    static public PREFIX[] prefix = new PREFIX[0x100];
	static {
		if (Log.level<=LogSeverities.LOG_NORMAL) {
			try {
				FileOutputStream fos = new FileOutputStream("inslog.txt");
				osw = new OutputStreamWriter(fos);
			} catch (Throwable t) {

			}
		}
		
		prefix[0xF0] = new PREFIX() {
			final public void call() {//LOCK
				logWrite("LOCK");
			}
		};

		prefix[0xF2] = new PREFIX() {
			final public void call() {//REPNZ
				Core.prefixes |= Core.PREFIX_REP;
				Core.rep_zero = false;
				logWrite("REPNZ");
			}
		};

		prefix[0xF3] = new PREFIX() {
			final public void call() {//REPZ
				Core.prefixes |= Core.PREFIX_REP;
				Core.rep_zero = true;
				logWrite("REPZ");
			}
		};
		prefix[0x66] = new PREFIX() {
			final public void call() {//OPERAND-SIZE PREFIX O~l
				//System.out.println("fd87687876sa");
				Core.prefixes = Core.prefixes  | (Core.PREFIX_DW);
				logWrite("DW");
			}
		};

		prefix[0x26] = new PREFIX() {
			final public void call() {//SEGMENT OVERRIDE O~l
				logWrite(CPU.DO_PREFIX_SEG_index(0));
			}
		};

		prefix[0x2e] = new PREFIX() {
			final public void call() {
				logWrite(CPU.DO_PREFIX_SEG_index(1));
			}
		};

		prefix[0x36] = new PREFIX() {
			final public void call() {
				logWrite(CPU.DO_PREFIX_SEG_index(2));
			}
		};

		prefix[0x3e] = new PREFIX() {
			final public void call() {
				logWrite(CPU.DO_PREFIX_SEG_index(3));
			}
		};

		prefix[0x64] = new PREFIX() {
			final public void call() {
				logWrite(CPU.DO_PREFIX_SEG_index(4));
			}
		};

		prefix[0x65] = new PREFIX() {
			final public void call() {
				logWrite(CPU.DO_PREFIX_SEG_index(5));
			}
		};

		prefix[0x0F] = new PREFIX() {
			final public void call() {
				curOps = CodeExt.ops;
			}
		};

		//OPCODE 1 OR 2
//		if (c == ) {
//			c = 0x100 + Fetchb();
//			logIns(c);
//		}
	}
	static OP[] curOps;
	public static CPU.CPU_Decoder CPU_Core_Normal_Run = new CPU.CPU_Decoder() {
		public /*Bits*/int call() {
			//System.out.println("CPU_Core_Normal_Run");
			while (CPU.CPU_Cycles-- > 0) {
				// inlined
				//LOADIP();
				Core.cseip = CPU_Regs.reg_csPhys + CPU_Regs.reg_eip;
				Core.prefixes = 0;
				Core.base_ds = CPU_Regs.reg_dsPhys;
				Core.base_ss = CPU_Regs.reg_ssPhys;
				
				curOps = Code.ops;
				
				logIns(Core.cseip);
				int c;
				while (true) {
					c = Core.Fetchb();
					logIns(c);
					PREFIX pfx = prefix[c];
					if(pfx!=null) {
						pfx.call();
						continue;
					}
					break;
				}

				//MODR/M 0 OR l
				//SIB 0 OR l
				//DISPLACEMENT 0,1,2 OR 4
				//IMMEDIATE 0,1,2 OR 4
				if ((Core.prefixes & Core.PREFIX_DW) != 0) {
					int i=1;
				}
				OP op = curOps[c];
				int result = op.call();
				logWrite(op.toString());
				logInsNewLine();
				if (result == Prefix_helpers.HANDLED) {
					CPU_Regs.reg_eip = Core.cseip - CPU_Regs.reg_csPhys;
				} else {
					if (result == Prefix_helpers.CONTINUE) {
					} else if (result == Prefix_helpers.RETURN) {
						return CPU.returnValue;
					} else if (result == Prefix_helpers.CBRET_NONE) {
						return Callback.CBRET_NONE;
					} else if (result == Prefix_helpers.NOT_HANDLED || result == Prefix_helpers.ILLEGAL_OPCODE) {
						if (Config.C_DEBUG) {
							/*Bitu*/int len = Prefix_helpers.GETIP() - Core.reg_eip;
							Prefix_helpers.LOADIP();
							if (len > 16) len = 16;
							StringBuffer tempcode = new StringBuffer();
							for (; len > 0; len--) {
								tempcode.append(Integer.toHexString(Memory.mem_readb(Core.cseip++)));
							}
						}
						if (Log.level <= LogSeverities.LOG_NORMAL) Log.log(LogTypes.LOG_CPU, LogSeverities.LOG_NORMAL, "Illegal/Unhandled opcode " + Integer.toHexString(c));
						CPU.CPU_Exception(6, 0);
					}
				}

			}
			Flags.FillFlags();
			return Callback.CBRET_NONE;
		}
	};

}
